{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "params = {\n",
    "    'leverage': 5,          # 杠杆倍数\n",
    "    'stop_loss_pct': 0.03,  # 止损比例（3%）\n",
    "    'take_profit_pct': 0.05,# 止盈比例（5%）\n",
    "    'commission_rate': 0.0002,  # 手续费率（万二）\n",
    "    'position_ratio': 0.8   # 单次开仓资金占比（80%）\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 限价单与杠杆仓位计算\n",
    "def calculate_position(cash, price, leverage):\n",
    "    max_position = cash * leverage / price  # 杠杆允许的最大持仓量\n",
    "    actual_position = max_position * params[\"position_ratio\"]\n",
    "    return int(actual_position)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 动态止盈止损逻辑\n",
    "def update_stop_loss(current_price, entry_price):\n",
    "    # 初始止损价 = 成本价 × (1 - 止损比例)\n",
    "    initial_stop = entry_price * (1 - params[\"stop_loss_pct\"])\n",
    "    # 动态跟踪：若价格上涨，止损价上移\n",
    "    dynamic_stop = max(initial_stop, current_price * (1 - params[\"stop_loss_pct\"]))\n",
    "    return dynamic_stop\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 止盈触发条件\n",
    "def check_take_profit(current_price, entry_price):\n",
    "    return current_price >= entry_price * (1 + params[\"take_profit_pct\"])\n",
    "    \n",
    "# 杠杆风险监控\n",
    "def check_margin(cash, position, current_price, leverage):\n",
    "    # 计算维持保证金要求\n",
    "    maintenance_margin = position * current_price / leverage\n",
    "    return cash >= maintenance_margin\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 回测框架设计\n",
    "class Backtest:\n",
    "    def __init__(self, data):\n",
    "        self.data = data\n",
    "        self.cash = 1e6       # 初始资金100万\n",
    "        self.position = 0      # 当前持仓量\n",
    "        self.entry_price = 0   # 持仓成本价\n",
    "\n",
    "    def execute_order(self, price, quantity, is_buy):\n",
    "        # 计算手续费和实际成交金额\n",
    "        commission = price * quantity * params['commission_rate']\n",
    "        total_cost = price * quantity + commission\n",
    "        if is_buy:\n",
    "            self.cash -= total_cost\n",
    "            self.position += quantity\n",
    "            self.entry_price = price\n",
    "        else:\n",
    "            self.cash += price * quantity - commission\n",
    "            self.position -= quantity\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"最终资金: {self.cash:.2f}\")\n",
    "print(f\"总收益率: {(self.cash / 1e6 - 1) * 100:.2f}%\")\n",
    "# 可视化资金曲线\n",
    "plt.plot(equity_curve)\n",
    "plt.title(\"Strategy Performance with Leverage\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import talib\n",
    "import yfinance as yf\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "class MACDKDJRSI:\n",
    "    def __init__(self, period=\"1y\", interval=\"1d\"):\n",
    "        self.period = period\n",
    "        self.interval = interval\n",
    "\n",
    "        self.get_data()\n",
    "        self.calculate()\n",
    "    \n",
    "    def calculate(self):\n",
    "        self.calculate_all()\n",
    "        self.marketing()\n",
    "\n",
    "    def get_data(self):\n",
    "        # 获取历史数据（示例用AAPL）\n",
    "        # start = \"2024-01-01\"\n",
    "        # end = \"2025-02-26\"\n",
    "        self.df = yf.download(\n",
    "            tickers=\"BTC-USD\", period=self.period, interval=self.interval\n",
    "        )\n",
    "        # 1d season\n",
    "        # 1h 3day\n",
    "        # 30m day\n",
    "        # 15m day\n",
    "\n",
    "    # ----------------------------\n",
    "    # 1. 计算MACD指标（参考‌:ml-citation{ref=\"4\" data=\"citationList\"}实现）\n",
    "    # ----------------------------\n",
    "    def calculate_macd(self):\n",
    "        # 计算MACD指标\n",
    "        # (\n",
    "        #     self.df[\"MACD\"],\n",
    "        #     self.df[\"MACD_Signal_Line\"],\n",
    "        #     self.df[\"Histogram\"],\n",
    "        # ) = talib.MACD(\n",
    "        #     self.df[\"Close\"].values.flatten(), fastperiod=12, slowperiod=26, signalperiod=9\n",
    "        # )\n",
    "\n",
    "        self.df[\"EMA12\"] = self.df[\"Close\"].ewm(span=12, adjust=False).mean()\n",
    "        self.df[\"EMA26\"] = self.df[\"Close\"].ewm(span=26, adjust=False).mean()\n",
    "        self.df[\"DIF\"] = self.df[\"EMA12\"] - self.df[\"EMA26\"]\n",
    "        self.df[\"DEA\"] = self.df[\"DIF\"].ewm(span=9, adjust=False).mean()\n",
    "        self.df[\"MACD\"] = (self.df[\"DIF\"] - self.df[\"DEA\"]) * 2\n",
    "        # return self.df\n",
    "\n",
    "    # ----------------------------\n",
    "    # 2. 计算KDJ指标（参考‌:ml-citation{ref=\"4,6\" data=\"citationList\"}实现）\n",
    "    # ----------------------------\n",
    "    def calculate_kdj(self, n=9, m1=3, m2=3):\n",
    "        low_min = self.df[\"Low\"].rolling(n, min_periods=1).min()\n",
    "        high_max = self.df[\"High\"].rolling(n, min_periods=1).max()\n",
    "        self.df[\"RSV\"] = (self.df[\"Close\"] - low_min) / (high_max - low_min) * 100\n",
    "        self.df[\"K\"] = self.df[\"RSV\"].ewm(alpha=1 / m1, adjust=False).mean()\n",
    "        self.df[\"D\"] = self.df[\"K\"].ewm(alpha=1 / m2, adjust=False).mean()\n",
    "        self.df[\"J\"] = 3 * self.df[\"K\"] - 2 * self.df[\"D\"]\n",
    "\n",
    "    # 3.计算RSI\n",
    "    def calculate_rsi(self, window=14):\n",
    "        # 提取收盘价序列\n",
    "        close = self.df[\"Close\"]\n",
    "\n",
    "        # 计算价格变化差值\n",
    "        delta = close.diff(1)\n",
    "\n",
    "        # 分离涨跌幅\n",
    "        gain = delta.where(delta > 0, 0)\n",
    "        loss = -delta.where(delta < 0, 0)\n",
    "\n",
    "        # 计算平均涨跌幅（使用指数移动平均）\n",
    "        avg_gain = gain.ewm(alpha=1 / window, min_periods=window).mean()\n",
    "        avg_loss = loss.ewm(alpha=1 / window, min_periods=window).mean()\n",
    "\n",
    "        # 计算RS和RSI\n",
    "        rs = avg_gain / avg_loss\n",
    "        self.df[\"RSI\"] = 100 - (100 / (1 + rs))\n",
    "\n",
    "    # 执行计算\n",
    "    def calculate_all(self):\n",
    "        self.calculate_macd()\n",
    "        self.calculate_kdj()\n",
    "        self.calculate_rsi()\n",
    "        self.df = self.df.fillna(0)\n",
    "\n",
    "    def marketing(self):\n",
    "        # ----------------------------\n",
    "        # 3. 生成交易信号\n",
    "        # ----------------------------\n",
    "        # MACD金叉/死叉判断\n",
    "        self.df[\"MACD_Cross\"] = np.where(self.df[\"DIF\"] > self.df[\"DEA\"], 1, -1)\n",
    "        self.df[\"MACD_Signal\"] = self.df[\"MACD_Cross\"].diff()\n",
    "\n",
    "        # KDJ超买超卖判断（J>80超买，J<20超卖）\n",
    "        self.df[\"KDJ_Over\"] = np.where(self.df[\"J\"] > self.df[\"D\"], 1, -1)\n",
    "        # data[\"KDJ_Over\"] = (data[\"J\"] > data[\"D\"]) & data[\"J\"]<50\n",
    "\n",
    "        # 综合信号（MACD金叉+KDJ超卖时买入且RSI小于70时买入）\n",
    "        self.df[\"Buy_Signal\"] = (\n",
    "            (self.df[\"MACD_Signal\"] > 0) & (self.df[\"KDJ_Over\"] == 1)\n",
    "        ) & (self.df[\"RSI\"] < 80)\n",
    "        self.df[\"Sell_Signal\"] = (\n",
    "            (self.df[\"MACD_Signal\"] < 0) & (self.df[\"KDJ_Over\"] == -1)\n",
    "        ) & (self.df[\"RSI\"] > 30)\n",
    "\n",
    "        # print(data.head(10))\n",
    "\n",
    "        # filter_data = self.df[(self.df[\"Buy_Signal\"]) | (self.df[\"Sell_Signal\"])]\n",
    "        #\n",
    "        # print(filter_data.head(100))\n",
    "\n",
    "        # data.head(500)\n",
    "\n",
    "    # ----------------------------\n",
    "    # 4. 回测展示（简化版）\n",
    "    # ----------------------------\n",
    "\n",
    "    # 数据可视化\n",
    "    def backtest(self):\n",
    "        plt.figure(figsize=(16, 12))\n",
    "        # 价格与MACD\n",
    "        plt.subplot(4, 1, 1)\n",
    "        plt.plot(self.df[\"Close\"], label=\"Price\")\n",
    "        plt.plot(\n",
    "            self.df[self.df[\"Buy_Signal\"]].index,\n",
    "            self.df[\"Close\"][self.df[\"Buy_Signal\"]],\n",
    "            \"^\",\n",
    "            markersize=10,\n",
    "            color=\"r\",\n",
    "        )\n",
    "        plt.plot(\n",
    "            self.df[self.df[\"Sell_Signal\"]].index,\n",
    "            self.df[\"Close\"][self.df[\"Sell_Signal\"]],\n",
    "            \"v\",\n",
    "            markersize=10,\n",
    "            color=\"g\",\n",
    "        )\n",
    "\n",
    "        # MACD指标\n",
    "        plt.subplot(4, 1, 2)\n",
    "        plt.plot(self.df[\"DIF\"], label=\"DIF\")\n",
    "        plt.plot(self.df[\"DEA\"], label=\"DEA\")\n",
    "        plt.bar(\n",
    "            self.df.index,\n",
    "            self.df[\"MACD\"],\n",
    "            label=\"MACD Histogram\",\n",
    "            color=[(\"red\" if x > 0 else \"green\") for x in self.df[\"MACD\"]],\n",
    "            alpha=0.5,\n",
    "        )\n",
    "        plt.legend(loc=\"lower left\", frameon=False)\n",
    "        # plt.bar(\n",
    "        #     data.index,\n",
    "        #     data[\"Histogram\"],\n",
    "        #     color=[(\"red\" if x > 0 else \"green\") for x in data[\"Histogram\"]],\n",
    "        #     alpha=0.5,\n",
    "        # )\n",
    "\n",
    "        # KDJ指标\n",
    "        plt.subplot(4, 1, 3)\n",
    "        plt.plot(self.df[\"K\"], label=\"K\")\n",
    "        plt.plot(self.df[\"D\"], label=\"D\")\n",
    "        plt.plot(self.df[\"J\"], label=\"J\")\n",
    "        plt.axhline(80, linestyle=\"--\", color=\"gray\")\n",
    "        plt.axhline(20, linestyle=\"--\", color=\"gray\")\n",
    "        plt.legend(loc=\"lower left\", frameon=False)\n",
    "\n",
    "        # RSI绘制\n",
    "        plt.subplot(4, 1, 4)\n",
    "        plt.plot(self.df[\"RSI\"], color=\"navy\")\n",
    "        plt.fill_between(self.df.index, 30, 70, color=\"lightgrey\", alpha=0.3)\n",
    "        plt.axhline(70, color=\"red\", linewidth=0.5)\n",
    "        plt.axhline(30, color=\"green\", linewidth=0.5)\n",
    "\n",
    "        plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import backtrader as bt\n",
    "\n",
    "\n",
    "class LimitOrderStrategy(bt.Strategy):\n",
    "    params = (\n",
    "        (\"leverage\", 20),\n",
    "        (\"stop_loss\", 0.08),\n",
    "        (\"take_profit\", 0.22),\n",
    "    )\n",
    "\n",
    "    def __init__(self):\n",
    "        self.data_close = self.datas[0]().close\n",
    "\n",
    "    def next(self):\n",
    "        if not self.position:\n",
    "            # check can buy\n",
    "            if self.datas[0][\"Buy_Signal\"]:\n",
    "                # 限价买入（现价上浮1%）\n",
    "                buy_price = self.data_close[0]() * 1.01\n",
    "                self.buy_bracket(\n",
    "                    price=buy_price,\n",
    "                    stopprice=buy_price * (1 - self.p.stop_loss),\n",
    "                    limitprice=buy_price * (1 + self.p.take_profit),\n",
    "                    exectype=bt.Order.Limit,\n",
    "                )\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    mjr = MACDKDJRSI()\n",
    "    cerebro = bt.Cerebro()\n",
    "    data = bt.feeds.YahooFinanceData(dataname=\"BTC-USD\", period=\"3d\")\n",
    "    mjr.df = data\n",
    "    mjr.calculate()\n",
    "    cerebro.adddata(mjr.df)\n",
    "    cerebro.addstrategy(LimitOrderStrategy)\n",
    "    cerebro.addanalyzer(bt.analyzers.SharpeRatio,  _name='sharpe')\n",
    "    cerebro.addanalyzer(bt.analyzers.DrawDown,  _name='drawdown')\n",
    "\n",
    "    cerebro.broker.set_cash(100000)  # 初始资金\n",
    "    cerebro.broker.setcommission(commission=0.005, leverage=20)  # 佣金 杠杆\n",
    "\n",
    "    cerebro.run()\n",
    "    cerebro.plot()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import yfinance as yf\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# 数据获取与处理\n",
    "data = yf.download(\"BTC-USD\", period=\"1y\")\n",
    "data[\"SMA20\"] = data[\"Close\"].rolling(20).mean()\n",
    "data[\"ATR\"] = data[\"High\"] - data[\"Low\"]\n",
    "\n",
    "# 策略逻辑\n",
    "leverage = 5  # 杠杆倍数\n",
    "positions = []\n",
    "cash = 100000  # 初始资金\n",
    "\n",
    "for i in range(20, len(data)):\n",
    "    current_price = data[\"Close\"][i]\n",
    "    # 做多信号：价格上穿均线\n",
    "    if data[\"Close\"][i] > data[\"SMA20\"][i]:\n",
    "        entry_price = current_price * 0.99  # 限价入场\n",
    "        stop_loss = entry_price * 0.98\n",
    "        take_profit = entry_price * 1.05\n",
    "        position_size = (cash * leverage) // entry_price\n",
    "        # 更新持仓和资金...\n",
    "    # 做空信号同理...\n",
    "\n",
    "# 输出回测结果\n",
    "print(f\"最终资金: {cash}\")\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
